
#include "VxIrrLib.h"
#include "bullet/BulletCollision/CollisionDispatch/btGhostObject.h"
//============================================================================
//=== constructor ===//
IrrPhysBase::IrrPhysBase()
	: m_poPhysCollisionConfiguration(0)
	, m_poPhysDispatcher(0)
	, m_poPhysPairCache(0)
	, m_poPhysConstraintSolver(0)
	, m_poPhysDynamicsWorld(0)
	, m_f32PhysContactBreakingThreshold(0.0f)
	, m_f32PhysWorldScaling(0.0f)
	, m_f32PhysPlayerForwardBackward(0.0f)
	, m_f32PhyPlayerSideways(0.0f)
	, m_iPhysCreatedObjectsCnt(0)
	, m_iPhysUpdatedBodiesCnt(0)
	, m_poIrrBase(0)
{
}
//============================================================================
//=== destructor ===//
IrrPhysBase::~IrrPhysBase()
{
}
//============================================================================
//! initialize physics
void IrrPhysBase::PhysStartup( VxIrrBase * poIrrBase )
{
	m_poIrrBase = poIrrBase;
	m_f32PhysContactBreakingThreshold = 0.1f;

	// setup the main Bullet datastructures
	m_poPhysCollisionConfiguration	= new btDefaultCollisionConfiguration();
	m_poPhysCollisionConfiguration->setConvexConvexMultipointIterations();
	m_poPhysDispatcher				= new btCollisionDispatcher(m_poPhysCollisionConfiguration);
	m_poPhysPairCache				= new btDbvtBroadphase();
	m_poPhysConstraintSolver		= new btSequentialImpulseConstraintSolver();
	
	// create the main Bullet dynamics world
	m_poPhysDynamicsWorld			= new btDiscreteDynamicsWorld(	m_poPhysDispatcher,
																	m_poPhysPairCache,
																	m_poPhysConstraintSolver,
																	m_poPhysCollisionConfiguration );
	// setup gravity
	//m_poPhysDynamicsWorld->setGravity(btVector3( 0, -100 * m_f32PhysWorldScaling, 0));
	m_poPhysDynamicsWorld->setGravity( btVector3( 0.0f, 0.0f, 0.0f ) );
	
	// register an additional callback for characters/ghost objects
	m_poPhysDynamicsWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());

	//link Bullet debug drawer
	IrrPhysDebugDrawer * poPhysDebugDrawer = new IrrPhysDebugDrawer( m_poIrrBase->m_poDriver );

	m_poPhysDynamicsWorld->setDebugDrawer( poPhysDebugDrawer );
	//IrrPhysDebugDrawer( irr::video::IVideoDriver* poVidDriver );

	m_poPhysDynamicsWorld->getDebugDrawer()->setDebugMode( btIDebugDraw::DBG_DrawWireframe );
}
//============================================================================
//! shutdown physics
void IrrPhysBase::PhysShutdown( void )
{
}

//============================================================================
//! run physics
void IrrPhysBase::PhysStep( U32 u32MilliSec )
{
	if( m_poPhysDynamicsWorld )
	{
		// limit milliseconds in case of system hicup
		if( u32MilliSec > 200 )
		{
			u32MilliSec = 200;
		}
		m_poPhysDynamicsWorld->stepSimulation( u32MilliSec * 0.001f );
		// Handle collisions
		int iManifoldCount = m_poPhysDynamicsWorld->getDispatcher()->getNumManifolds();
		for(int i = 0; i < iManifoldCount; i++) 
		{
			btPersistentManifold * poContactManifold = m_poPhysDynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
			if( poContactManifold->getNumContacts() > 0) 
			{
				btCollisionObject *CollisionObject0 = static_cast<btCollisionObject *>( poContactManifold->getBody0() );
				btCollisionObject *CollisionObject1 = static_cast<btCollisionObject *>( poContactManifold->getBody1() );
				
				EntBase * poEnt0 = static_cast<EntBase *>(CollisionObject0->getUserPointer());
				EntBase * poEnt1 = static_cast<EntBase *>(CollisionObject1->getUserPointer());

				if( poEnt0->HandleCollision( poEnt1, poContactManifold, 1 ) )
				{
					break;
				}
				if( poEnt1->HandleCollision( poEnt0, poContactManifold, -1 ) )
				{
					break;
				}
			}
		}
	}
}
//============================================================================
//! raycast into world.. return true if collision occured
BOOL IrrPhysBase::RaycastWorld(	const btVector3&	vec3Start,		// starting point of ray
								btVector3&			vec3RetEnd,		// ending point of ray 
								btVector3&			vec3RetNormal,	// return normal of collision point
								EPhysFilterTypes	eCollideMask )  // mask of collision groups to check for collision
{
	btCollisionWorld::ClosestRayResultCallback RayCallback( vec3Start, vec3RetEnd );
	// only test for collision with camera
	RayCallback.m_collisionFilterMask = eCollideMask;

	// do raycast
	m_poPhysDynamicsWorld->rayTest( vec3Start, vec3RetEnd, RayCallback );
	if( RayCallback.hasHit() ) 
	{
		// ray collided.. return point of impact
		vec3RetEnd = RayCallback.m_hitPointWorld;
		vec3RetNormal = RayCallback.m_hitNormalWorld;
		return true;
	}
	return false;
}
